package cn.monkey.family.server.web.method;

import cn.monkey.family.data.QueryRequest;
import cn.monkey.family.data.Range;
import cn.monkey.family.data.shop.item.ItemQueryRequest;
import cn.monkey.family.data.shop.item.comment.CommentQueryRequest;
import cn.monkey.family.data.shop.item.type.ItemTypeQueryRequest;
import cn.monkey.family.data.shop.order.OrderQueryRequest;
import cn.monkey.family.data.sys.address.AddressQueryRequest;
import cn.monkey.family.data.sys.address.AddressQueryRequests;
import cn.monkey.family.data.uc.org.OrgQueryRequest;
import cn.monkey.family.data.uc.resource.ResourceQueryRequest;
import cn.monkey.family.data.uc.role.RoleQueryRequest;
import cn.monkey.family.data.uc.user.UserQueryRequest;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.nio.charset.Charset;
import java.util.List;

public class QueryRequestArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return QueryRequest.class.isAssignableFrom(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        if (servletRequest == null) {
            throw HttpClientErrorException.create(HttpStatus.INTERNAL_SERVER_ERROR, "request is null", null, null, Charset.defaultCharset());
        }
        Function<String, String> paramResolveFunction = servletRequest::getParameter;
        Class<?> parameterType = parameter.getParameterType();
        if (parameterType.equals(RoleQueryRequest.class)) {
            return this.resolveRoleQueryRequest(paramResolveFunction);
        }
        if (parameterType.equals(OrgQueryRequest.class)) {
            return this.resolveOrgQueryRequest(paramResolveFunction);
        }
        if (parameterType.equals(UserQueryRequest.class)) {
            return this.resolveUserQueryRequest(paramResolveFunction);
        }
        if (parameterType.equals(ResourceQueryRequest.class)) {
            return this.resolveResourceQueryRequest(paramResolveFunction);
        }
        if (parameterType.equals(ItemQueryRequest.class)) {
            return this.resolveItemQueryRequest(paramResolveFunction);
        }
        if (parameterType.equals(OrderQueryRequest.class)) {
            return this.resolveOrderQueryRequest(paramResolveFunction);
        }
        if (parameterType.equals(AddressQueryRequest.class)) {
            return AddressQueryRequests.fromHttpServletRequest(servletRequest);
        }
        if (parameterType.equals(ItemTypeQueryRequest.class)) {
            return this.resolveItemTypeQueryRequest(paramResolveFunction);
        }
        if (parameterType.equals(CommentQueryRequest.class)) {
            return this.resolveCommentQueryRequest(paramResolveFunction);
        }
        throw new IllegalArgumentException("can not resolve parameter: " + parameterType);
    }

    private CommentQueryRequest resolveCommentQueryRequest(Function<String, String> paramResolveFunction) {
        return CommentQueryRequest.builder()
                .parentIds(this.toArray(paramResolveFunction.apply("parentId")))
                .build();
    }

    private ItemTypeQueryRequest resolveItemTypeQueryRequest(Function<String, String> paramResolveFunction) {
        return ItemTypeQueryRequest.builder()
                .parentKey(this.toList(paramResolveFunction.apply("parentKey")))
                .key(this.toList(paramResolveFunction.apply("key")))
                .build();
    }


    private String[] toArray(String s) {
        return Strings.isNullOrEmpty(s) ? null : s.split(",");
    }

    private List<String> toList(String s) {
        return Strings.isNullOrEmpty(s) ? null : List.of(s.split(","));
    }

    private OrderQueryRequest resolveOrderQueryRequest(Function<String, String> paramResolveFunction) {
        OrderQueryRequest.OrderQueryRequestBuilder builder = OrderQueryRequest.builder()
                .itemName(paramResolveFunction.apply("itemName"))
                .status(this.toArray(paramResolveFunction.apply("status")));
        String startCreateTime = paramResolveFunction.apply("startCreateTime");
        String endCreateTime = paramResolveFunction.apply("endCreateTime");
        if (!Strings.isNullOrEmpty(startCreateTime) || !Strings.isNullOrEmpty(endCreateTime)) {
            builder.createdTimeRange(Range.of(Long.parseLong(startCreateTime), Long.parseLong(endCreateTime)));
        }
        return builder.build();
    }

    private ResourceQueryRequest resolveResourceQueryRequest(Function<String, String> paramResolveFunction) {
        return ResourceQueryRequest.builder()
                .name(paramResolveFunction.apply("name"))
                .build();
    }

    private UserQueryRequest resolveUserQueryRequest(Function<String, String> paramResolveFunction) {
        return UserQueryRequest.builder()
                .account(paramResolveFunction.apply("name"))
                .email(paramResolveFunction.apply("email"))
                .mobile(paramResolveFunction.apply("mobile"))
                .build();
    }


    private ItemQueryRequest resolveItemQueryRequest(Function<String, String> paramResolveFunction) {
        String maxPrice = paramResolveFunction.apply("maxPrice");
        String minPrice = paramResolveFunction.apply("minPrice");
        ItemQueryRequest.ItemQueryRequestBuilder builder = ItemQueryRequest.builder()
                .name(paramResolveFunction.apply("name"))
                .tags(this.toArray(paramResolveFunction.apply("tag")));
        if (!Strings.isNullOrEmpty(minPrice) || !Strings.isNullOrEmpty(maxPrice)) {
            builder.priceRange(Range.of(Double.parseDouble(minPrice), Double.parseDouble(maxPrice)));
        }
        String type = paramResolveFunction.apply("type");
        if (!Strings.isNullOrEmpty(type)) {
            builder.type(this.toArray(type));
        }
        return builder.build();
    }

    private OrgQueryRequest resolveOrgQueryRequest(Function<String, String> paramResolveFunction) {
        return OrgQueryRequest.builder()
                .name(paramResolveFunction.apply("name"))
                .build();
    }


    private RoleQueryRequest resolveRoleQueryRequest(Function<String, String> paramResolveFunction) {
        return RoleQueryRequest.builder()
                .type(paramResolveFunction.apply("type"))
                .name(paramResolveFunction.apply("name"))
                .build();
    }
}
